/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#include "r_local.h"


#define NUM_VIDEO_MODES		(sizeof(r_videoModes) / sizeof(videoMode_t))

typedef struct {
	const char *	description;
	int				width;
	int				height;
} videoMode_t;

static videoMode_t	r_videoModes[] = {
	{"Mode  0: 320x240",			 320,  240},
	{"Mode  1: 400x300",			 400,  300},
	{"Mode  2: 512x384",			 512,  384},
	{"Mode  3: 640x480",			 640,  480},
	{"Mode  4: 800x600",			 800,  600},
	{"Mode  5: 960x720",			 960,  720},
	{"Mode  6: 1024x768",			1024,  768},
	{"Mode  7: 1152x864",			1152,  864},
	{"Mode  8: 1280x960",			1280,  960},
	{"Mode  9: 1280x1024",			1280, 1024},
	{"Mode 10: 1600x1200",			1600, 1200},
	{"Mode 11: 2048x1536",			2048, 1536},
	{"Mode 12: 640x400 (wide)",		 640,  400},
	{"Mode 13: 800x500 (wide)",		 800,  500},
	{"Mode 14: 960x600 (wide)",		 960,  600},
	{"Mode 15: 1024x640 (wide)",	1024,  640},
	{"Mode 16: 1280x800 (wide)",	1280,  800},
	{"Mode 17: 1440x900 (wide)",	1440,  900},
	{"Mode 18: 1600x1000 (wide)",	1600, 1000},
	{"Mode 19: 1680x1050 (wide)",	1680, 1050},
	{"Mode 20: 1920x1200 (wide)",	1920, 1200}
};

trGlobals_t			tr;

glConfig_t			glConfig;

cvar_t *			r_logFile;
cvar_t *			r_clear;
cvar_t *			r_clearColor;
cvar_t *			r_frontBuffer;
cvar_t *			r_screenFraction;
cvar_t *			r_portalSkyOnly;
cvar_t *			r_subviewOnly;
cvar_t *			r_lockVisibility;
cvar_t *			r_zNear;
cvar_t *			r_zFar;
cvar_t *			r_offsetFactor;
cvar_t *			r_offsetUnits;
cvar_t *			r_shadowOffsetFactor;
cvar_t *			r_shadowOffsetUnits;
cvar_t *			r_colorMipLevels;
cvar_t *			r_singleMaterial;
cvar_t *			r_singleEntity;
cvar_t *			r_singleLight;
cvar_t *			r_singleParticle;
cvar_t *			r_showCluster;
cvar_t *			r_showCull;
cvar_t *			r_showUpdates;
cvar_t *			r_showScene;
cvar_t *			r_showLeafs;
cvar_t *			r_showEntities;
cvar_t *			r_showMeshes;
cvar_t *			r_showInteractions;
cvar_t *			r_showShadows;
cvar_t *			r_showLights;
cvar_t *			r_showDynamic;
cvar_t *			r_showDeforms;
cvar_t *			r_showPrimitives;
cvar_t *			r_showVertexBuffers;
cvar_t *			r_showTextureUsage;
cvar_t *			r_showRenderToTexture;
cvar_t *			r_showBloom;
cvar_t *			r_showDepth;
cvar_t *			r_showOverdraw;
cvar_t *			r_showTris;
cvar_t *			r_showNormals;
cvar_t *			r_showTextureVectors;
cvar_t *			r_showTangentSpace;
cvar_t *			r_showVertexColors;
cvar_t *			r_showBatchSize;
cvar_t *			r_showSkeletons;
cvar_t *			r_showModelBounds;
cvar_t *			r_showShadowCount;
cvar_t *			r_showShadowTris;
cvar_t *			r_showShadowVolumes;
cvar_t *			r_showShadowSilhouettes;
cvar_t *			r_showLightCount;
cvar_t *			r_showLightVolumes;
cvar_t *			r_showLightScissors;
cvar_t *			r_skipVisibility;
cvar_t *			r_skipSuppress;
cvar_t *			r_skipCulling;
cvar_t *			r_skipInteractionCulling;
cvar_t *			r_skipShadowCulling;
cvar_t *			r_skipShadowProjectionCulling;
cvar_t *			r_skipShadowCapsCulling;
cvar_t *			r_skipLightCulling;
cvar_t *			r_skipUpdates;
cvar_t *			r_skipBatching;
cvar_t *			r_skipEntities;
cvar_t *			r_skipLights;
cvar_t *			r_skipParticles;
cvar_t *			r_skipDecals;
cvar_t *			r_skipFoliage;
cvar_t *			r_skipPrecompiledInteractions;
cvar_t *			r_skipPrecompiledShadows;
cvar_t *			r_skipExpressions;
cvar_t *			r_skipConstantExpressions;
cvar_t *			r_skipDeforms;
cvar_t *			r_skipAmbient;
cvar_t *			r_skipBump;
cvar_t *			r_skipDiffuse;
cvar_t *			r_skipSpecular;
cvar_t *			r_skipShadows;
cvar_t *			r_skipInteractions;
cvar_t *			r_skipFogLights;
cvar_t *			r_skipBlendLights;
cvar_t *			r_skipTranslucent;
cvar_t *			r_skipPostProcess;
cvar_t *			r_skipScissors;
cvar_t *			r_skipDepthBounds;
cvar_t *			r_skipPortalSky;
cvar_t *			r_skipSubviews;
cvar_t *			r_skipVideos;
cvar_t *			r_skipCopyToTextures;
cvar_t *			r_skipDynamicTextures;
cvar_t *			r_skipRender;
cvar_t *			r_skipRenderContext;
cvar_t *			r_skipFrontEnd;
cvar_t *			r_skipBackEnd;
cvar_t *			r_glDriver;
cvar_t *			r_ignoreGLErrors;
cvar_t *			r_multiSamples;
cvar_t *			r_alphaToCoverage;
cvar_t *			r_swapInterval;
cvar_t *			r_mode;
cvar_t *			r_fullscreen;
cvar_t *			r_customWidth;
cvar_t *			r_customHeight;
cvar_t *			r_displayRefresh;
cvar_t *			r_gamma;
cvar_t *			r_brightness;
cvar_t *			r_finish;
cvar_t *			r_vertexBuffers;
cvar_t *			r_bloom;
cvar_t *			r_bloomContrast;
cvar_t *			r_bloomMagnitude;
cvar_t *			r_bloomIntensity;
cvar_t *			r_lightScale;
cvar_t *			r_lightDetailLevel;
cvar_t *			r_shaderPrograms;
cvar_t *			r_shaderDetailLevel;
cvar_t *			r_roundTexturesDown;
cvar_t *			r_maxTextureSize;
cvar_t *			r_compressTextures;
cvar_t *			r_textureFilter;
cvar_t *			r_textureLODBias;
cvar_t *			r_textureAnisotropy;


/*
 ==================
 R_SetGamma
 ==================
*/
void R_SetGamma (void){

	float	invGamma, div;
	float	f;
	int		i;

	if (r_gamma->floatValue < 0.5f)
		CVar_SetFloat(r_gamma, 0.5f);
	else if (r_gamma->floatValue > 3.0f)
		CVar_SetFloat(r_gamma, 3.0f);

	r_gamma->modified = false;

	if (r_brightness->floatValue < 0.5f)
		CVar_SetFloat(r_brightness, 0.5f);
	else if (r_brightness->floatValue > 2.0f)
		CVar_SetFloat(r_brightness, 2.0f);

	r_brightness->modified = false;

	// Build gamma table
	invGamma = 1.0f / r_gamma->floatValue;
	div = r_brightness->floatValue / 255.0f;

	for (i = 0; i < 256; i++){
		f = 255.0f * M_Pow((float)i * div, invGamma) + 0.5f;

		tr.gammaTable[i] = M_ClampByte(M_Ftol(f));
	}

	// Set device gamma ramp
	GLImp_SetDeviceGammaRamp(tr.gammaTable);
}

/*
 ==================
 R_GetGLConfig

 Used by other subsystems to get the GL config
 ==================
*/
void R_GetGLConfig (glConfig_t *config){

	if (!config)
		Com_Error(true, "R_GetGLConfig: NULL config");

	*config = glConfig;
}

/*
 ==================
 R_GetVideoModeInfo
 ==================
*/
bool R_GetVideoModeInfo (int mode, int *width, int *height){

	if (mode == -1){
		if (r_customWidth->integerValue <= 1 || r_customHeight->integerValue <= 1)
			return false;

		*width = r_customWidth->integerValue;
		*height = r_customHeight->integerValue;

		return true;
	}

	if (mode < 0 || mode >= NUM_VIDEO_MODES)
		return false;

	*width = r_videoModes[mode].width;
	*height = r_videoModes[mode].height;

	return true;
}

/*
 ==================
 R_Benchmark_f
 ==================
*/
static void R_Benchmark_f (void){

	double	ticks, time;
	float	fraction;
	int		i, pixels;

	if (!tr.primaryViewAvailable){
		Com_Printf("No primaryView available for benchmarking\n");
		return;
	}

	CVar_SetFloat(r_screenFraction, 1.0f);
	CVar_SetInteger(r_skipInteractions, 0);
	CVar_SetInteger(r_skipRenderContext, 0);

	// Fillrate test
	for (fraction = 1.0f; fraction > 0.0f; fraction -= 0.1f){
		pixels = M_FtolFast(tr.primaryView.renderView.width * fraction) * M_FtolFast(tr.primaryView.renderView.height * fraction);

		CVar_SetFloat(r_screenFraction, fraction);

		ticks = Sys_GetClockTicks();

		for (i = 0; i < 50; i++){
			R_BeginFrame(tr.frameTime);
			R_RenderScene(tr.primaryView.scene, &tr.primaryView.renderView, true);
			R_EndFrame();
		}

		time = (Sys_GetClockTicks() - ticks) / Sys_ClockTicksPerSecond();

		Com_Printf("%-16s   msec:%8.2f   fps:%8.2f\n", Str_VarArgs("kpix:%11i", pixels / 1000), time * 1000.0 / 50.0, 50.0 / time);
	}

	CVar_SetFloat(r_screenFraction, 1.0f);

	// Interaction overdraw test
	CVar_SetInteger(r_skipInteractions, 1);

	ticks = Sys_GetClockTicks();

	for (i = 0; i < 50; i++){
		R_BeginFrame(tr.frameTime);
		R_RenderScene(tr.primaryView.scene, &tr.primaryView.renderView, true);
		R_EndFrame();
	}

	time = (Sys_GetClockTicks() - ticks) / Sys_ClockTicksPerSecond();

	Com_Printf("%-16s   msec:%8.2f   fps:%8.2f\n", "no interactions", time * 1000.0 / 50.0, 50.0 / time);

	CVar_SetInteger(r_skipInteractions, 0);

	// CPU performance test
	CVar_SetInteger(r_skipRenderContext, 1);

	ticks = Sys_GetClockTicks();

	for (i = 0; i < 50; i++){
		R_BeginFrame(tr.frameTime);
		R_RenderScene(tr.primaryView.scene, &tr.primaryView.renderView, true);
		R_EndFrame();
	}

	time = (Sys_GetClockTicks() - ticks) / Sys_ClockTicksPerSecond();

	Com_Printf("%-16s   msec:%8.2f   fps:%8.2f\n", "no context", time * 1000.0 / 50.0, 50.0 / time);

	CVar_SetInteger(r_skipRenderContext, 0);
}

/*
 ==================
 R_ListVideoModes_f
 ==================
*/
static void R_ListVideoModes_f (void){

	int i;

	Com_Printf("Mode -1: %ix%i (custom)\n", r_customWidth->integerValue, r_customHeight->integerValue);

	for (i = 0; i < NUM_VIDEO_MODES; i++)
		Com_Printf("%s\n", r_videoModes[i].description);
}

/*
 ==================
 R_GfxInfo_f
 ==================
*/
static void R_GfxInfo_f (void){

	Com_Printf("\n");
	Com_Printf("GL_VENDOR: %s\n", glConfig.vendorString);
	Com_Printf("GL_RENDERER: %s\n", glConfig.rendererString);
	Com_Printf("GL_VERSION: %s\n", glConfig.versionString);
	Com_Printf("GL_EXTENSIONS: %s\n", glConfig.extensionsString);
	Com_Printf("WGL_EXTENSIONS: %s\n", glConfig.wglExtensionsString);
	Com_Printf("\n");
	Com_Printf("GL_SHADING_LANGUAGE_VERSION: %s\n", glConfig.shadingLanguageVersionString);
	Com_Printf("\n");
	Com_Printf("GL_MAX_TEXTURE_SIZE: %i\n", glConfig.maxTextureSize);
	Com_Printf("GL_MAX_CUBE_MAP_TEXTURE_SIZE: %i\n", glConfig.maxCubeMapTextureSize);
	Com_Printf("GL_MAX_TEXTURE_UNITS: %i\n", glConfig.maxTextureUnits);
	Com_Printf("GL_MAX_TEXTURE_COORDS: %i\n", glConfig.maxTextureCoords);
	Com_Printf("GL_MAX_TEXTURE_IMAGE_UNITS: %i\n", glConfig.maxTextureImageUnits);
	Com_Printf("GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: %i\n", glConfig.maxVertexTextureImageUnits);
	Com_Printf("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %i\n", glConfig.maxCombinedTextureImageUnits);
	Com_Printf("GL_MAX_VERTEX_ATTRIBS: %i\n", glConfig.maxVertexAttribs);
	Com_Printf("GL_MAX_VARYING_FLOATS: %i\n", glConfig.maxVaryingFloats);
	Com_Printf("GL_MAX_VERTEX_UNIFORM_COMPONENTS: %i\n", glConfig.maxVertexUniformComponents);
	Com_Printf("GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: %i\n", glConfig.maxFragmentUniformComponents);
	Com_Printf("GL_MAX_TEXTURE_LOD_BIAS: %.1f\n", glConfig.maxTextureLODBias);
	Com_Printf("GL_MAX_TEXTURE_MAX_ANISOTROPY: %.1f\n", glConfig.maxTextureMaxAnisotropy);
	Com_Printf("\n");
	Com_Printf("PIXELFORMAT: color(%i-bits) alpha(%i-bits) depth(%i-bits) stencil(%i-bits)\n", glConfig.colorBits, glConfig.alphaBits, glConfig.depthBits, glConfig.stencilBits);
	Com_Printf("MODE: %i, %i x %i %s%s\n", r_mode->integerValue, glConfig.videoWidth, glConfig.videoHeight, (glConfig.isFullscreen) ? "fullscreen" : "windowed", (glConfig.displayFrequency) ? Str_VarArgs(" (%i Hz)", glConfig.displayFrequency) : "");
	Com_Printf("SAMPLES: %s\n", (glConfig.samples) ? Str_VarArgs("%ix", glConfig.samples) : "none");
	Com_Printf("CPU: %s\n", Sys_GetProcessorString());
	Com_Printf("\n");

	if (glConfig.textureFilterAnisotropicAvailable)
		Com_Printf("Using %s texture filtering w/ %.1f anisotropy\n", r_textureFilter->value, r_textureAnisotropy->floatValue);
	else
		Com_Printf("Using %s texture filtering\n", r_textureFilter->value);

	if (r_compressTextures->integerValue > 0)
		Com_Printf("Using texture compression\n");
	else
		Com_Printf("Texture compression is disabled\n");

	if (r_vertexBuffers->integerValue)
		Com_Printf("Using vertex buffers\n");
	else
		Com_Printf("Vertex buffers are disabled\n");

	if (r_shaderPrograms->integerValue)
		Com_Printf("Using shader programs\n");
	else
		Com_Printf("Shader programs are disabled\n");

	if (glConfig.depthBoundsTestAvailable)
		Com_Printf("Using depth bounds testing\n");
	else
		Com_Printf("Depth bounds testing not available\n");

	if (glConfig.swapControlAvailable && r_swapInterval->integerValue)
		Com_Printf("Forcing swapInterval %i\n", r_swapInterval->integerValue);
	else
		Com_Printf("swapInterval not forced\n");

	if (r_finish->integerValue)
		Com_Printf("Forcing glFinish\n");
	else
		Com_Printf("glFinish not forced\n");

	Com_Printf("\n");
}

/*
 ==================
 R_Register
 ==================
*/
static void R_Register (void){

	r_logFile = CVar_Get("r_logFile", "0", CVAR_CHEAT, "Number of frames to log GL calls");
	r_clear = CVar_Get("r_clear", "0", CVAR_CHEAT, "Clear the color buffer");
	r_clearColor = CVar_Get("r_clearColor", "0", CVAR_CHEAT, "Color index for clearing the color buffer");
	r_frontBuffer = CVar_Get("r_frontBuffer", "0", CVAR_CHEAT, "Render to the front buffer for debugging");
	r_screenFraction = CVar_Get("r_screenFraction", "1.0", CVAR_CHEAT, "Render to a fraction of the screen for testing fillrate");
	r_portalSkyOnly = CVar_Get("r_portalSkyOnly", "0", CVAR_CHEAT, "Only render portal skies for debugging");
	r_subviewOnly = CVar_Get("r_subviewOnly", "0", CVAR_CHEAT, "Only render subviews for debugging");
	r_lockVisibility = CVar_Get("r_lockVisibility", "0", CVAR_CHEAT, "Don't update visibility when the camera moves");
	r_zNear = CVar_Get("r_zNear", "3.0", CVAR_CHEAT, "Near clip plane distance");
	r_zFar = CVar_Get("r_zFar", "0.0", CVAR_CHEAT, "Far clip plane distance (0 = infinite)");
	r_offsetFactor = CVar_Get("r_offsetFactor", "-1.0", CVAR_CHEAT, "Polygon offset factor");
	r_offsetUnits = CVar_Get("r_offsetUnits", "-2.0", CVAR_CHEAT, "Polygon offset units");
	r_shadowOffsetFactor = CVar_Get("r_shadowOffsetFactor", "0.01", CVAR_CHEAT, "Shadow polygon offset factor");
	r_shadowOffsetUnits = CVar_Get("r_shadowOffsetUnits", "1.0", CVAR_CHEAT, "Shadow polygon offset units");
	r_colorMipLevels = CVar_Get("r_colorMipLevels", "0", CVAR_CHEAT | CVAR_LATCH, "Color mip levels for testing mipmap usage");
	r_singleMaterial = CVar_Get("r_singleMaterial", "0", CVAR_CHEAT | CVAR_LATCH, "Use a single default material on every mesh");
	r_singleEntity = CVar_Get("r_singleEntity", "-1", CVAR_CHEAT, "Only draw the specified entity");
	r_singleLight = CVar_Get("r_singleLight", "-1", CVAR_CHEAT, "Only draw the specified light");
	r_singleParticle = CVar_Get("r_singleParticle", "-1", CVAR_CHEAT, "Only draw the specified particle");
	r_showCluster = CVar_Get("r_showCluster", "0", CVAR_CHEAT, "Show the current view cluster and area");
	r_showCull = CVar_Get("r_showCull", "0", CVAR_CHEAT, "Show culling statistics");
	r_showUpdates = CVar_Get("r_showUpdates", "0", CVAR_CHEAT, "Show number of entity/light/particle updates");
	r_showScene = CVar_Get("r_showScene", "0", CVAR_CHEAT, "Show number of entities/lights/particles/decals in view");
	r_showLeafs = CVar_Get("r_showLeafs", "0", CVAR_CHEAT, "Show number of leafs in view");
	r_showEntities = CVar_Get("r_showEntities", "0", CVAR_CHEAT, "Show number of entities in view");
	r_showMeshes = CVar_Get("r_showMeshes", "0", CVAR_CHEAT, "Show number of meshes in view");
	r_showInteractions = CVar_Get("r_showInteractions", "0", CVAR_CHEAT, "Show interaction generation statistics");
	r_showShadows = CVar_Get("r_showShadows", "0", CVAR_CHEAT, "Show shadow generation statistics");
	r_showLights = CVar_Get("r_showLights", "0", CVAR_CHEAT, "Show number of lights in view (2 = also print volume numbers highlighting the ones covering the view)");
	r_showDynamic = CVar_Get("r_showDynamic", "0", CVAR_CHEAT, "Show dynamic mesh generation statistics");
	r_showDeforms = CVar_Get("r_showDeforms", "0", CVAR_CHEAT, "Show material deform statistics");
	r_showPrimitives = CVar_Get("r_showPrimitives", "0", CVAR_CHEAT, "Show view/draw/index/vertex counts");
	r_showVertexBuffers = CVar_Get("r_showVertexBuffers", "0", CVAR_CHEAT, "Show vertex buffer statistics");
	r_showTextureUsage = CVar_Get("r_showTextureUsage", "0", CVAR_CHEAT, "Show texture memory usage");
	r_showRenderToTexture = CVar_Get("r_showRenderToTexture", "0", CVAR_CHEAT, "Show render-to-texture statistics");
	r_showBloom = CVar_Get("r_showBloom", "0", CVAR_CHEAT, "Draw the bloom texture without blending");
	r_showDepth = CVar_Get("r_showDepth", "0", CVAR_CHEAT, "Draw the contents of the depth buffer");
	r_showOverdraw = CVar_Get("r_showOverdraw", "0", CVAR_CHEAT, "Draw triangles colored by overdraw (1 = geometry, 2 = interaction, 3 = geometry and interaction)");
	r_showTris = CVar_Get("r_showTris", "0", CVAR_CHEAT, "Draw triangles in wireframe mode (1 = draw visible ones, 2 = draw everything through walls)");
	r_showNormals = CVar_Get("r_showNormals", "0", CVAR_CHEAT, "Draw vertex normals");
	r_showTextureVectors = CVar_Get("r_showTextureVectors", "0", CVAR_CHEAT, "Draw texture (tangent) vectors");
	r_showTangentSpace = CVar_Get("r_showTangentSpace", "0", CVAR_CHEAT, "Draw triangles colored by tangent space (1 = 1st tangent, 2 = 2nd tangent, 3 = normal)");
	r_showVertexColors = CVar_Get("r_showVertexColors", "0", CVAR_CHEAT, "Draw triangles colored by vertex colors");
	r_showBatchSize = CVar_Get("r_showBatchSize", "0", CVAR_CHEAT, "Draw triangles colored by batch size (1 = draw visible ones, 2 = draw everything through walls)");
	r_showSkeletons = CVar_Get("r_showSkeletons", "0", CVAR_CHEAT, "Draw skeletons");
	r_showModelBounds = CVar_Get("r_showModelBounds", "0", CVAR_CHEAT, "Draw model bounds");
	r_showShadowCount = CVar_Get("r_showShadowCount", "0", CVAR_CHEAT, "Draw triangles colored by shadow count (1 = count all, 2 = only count static shadows, 3 = only count dynamic shadows)");
	r_showShadowTris = CVar_Get("r_showShadowTris", "0", CVAR_CHEAT, "Draw shadow triangles in wireframe mode (1 = draw visible ones, 2 = draw everything through walls)");
	r_showShadowVolumes = CVar_Get("r_showShadowVolumes", "0", CVAR_CHEAT, "Draw shadow planes");
	r_showShadowSilhouettes = CVar_Get("r_showShadowSilhouettes", "0", CVAR_CHEAT, "Draw shadow silhouettes");
	r_showLightCount = CVar_Get("r_showLightCount", "0", CVAR_CHEAT, "Draw triangles colored by light count (1 = count visible ones, 2 = count everything through walls)");
	r_showLightVolumes = CVar_Get("r_showLightVolumes", "0", CVAR_CHEAT, "Draw light volumes (1 = draw planes, 2 = draw edges, 3 = draw planes and edges)");
	r_showLightScissors = CVar_Get("r_showLightScissors", "0", CVAR_CHEAT, "Draw light scissor rectangles");
	r_skipVisibility = CVar_Get("r_skipVisibility", "0", CVAR_CHEAT, "Skip visibility determination tests");
	r_skipSuppress = CVar_Get("r_skipSuppress", "0", CVAR_CHEAT, "Skip per-view suppressions");
	r_skipCulling = CVar_Get("r_skipCulling", "0", CVAR_CHEAT, "Skip culling");
	r_skipInteractionCulling = CVar_Get("r_skipInteractionCulling", "0", CVAR_CHEAT, "Skip interaction culling");
	r_skipShadowCulling = CVar_Get("r_skipShadowCulling", "0", CVAR_CHEAT, "Skip shadow culling");
	r_skipShadowProjectionCulling = CVar_Get("r_skipShadowProjectionCulling", "0", CVAR_CHEAT, "Skip shadow projection culling");
	r_skipShadowCapsCulling = CVar_Get("r_skipShadowCapsCulling", "0", CVAR_CHEAT, "Skip shadow caps culling");
	r_skipLightCulling = CVar_Get("r_skipLightCulling", "0", CVAR_CHEAT, "Skip light culling");
	r_skipUpdates = CVar_Get("r_skipUpdates", "0", CVAR_CHEAT, "Skip entity/light/particle updates, making everything static");
	r_skipBatching = CVar_Get("r_skipBatching", "0", CVAR_CHEAT, "Skip geometry batching and issue a draw call per mesh");
	r_skipEntities = CVar_Get("r_skipEntities", "0", CVAR_CHEAT, "Skip rendering entities");
	r_skipLights = CVar_Get("r_skipLights", "0", CVAR_CHEAT, "Skip rendering lights");
	r_skipParticles = CVar_Get("r_skipParticles", "0", CVAR_CHEAT, "Skip rendering particles");
	r_skipDecals = CVar_Get("r_skipDecals", "0", CVAR_CHEAT, "Skip rendering decals");
	r_skipFoliage = CVar_Get("r_skipFoliage", "0", CVAR_CHEAT, "Skip rendering foliage");
	r_skipPrecompiledInteractions = CVar_Get("r_skipPrecompiledInteractions", "0", CVAR_CHEAT, "Skip precompiled interaction lists and generate them dynamically");
	r_skipPrecompiledShadows = CVar_Get("r_skipPrecompiledShadows", "0", CVAR_CHEAT, "Skip precompiled shadow lists and generate them dynamically");
	r_skipExpressions = CVar_Get("r_skipExpressions", "0", CVAR_CHEAT, "Skip expression evaluation in materials");
	r_skipConstantExpressions = CVar_Get("r_skipConstantExpressions", "0", CVAR_CHEAT, "Skip constant expressions in materials, re-evaluating everything each frame");
	r_skipDeforms = CVar_Get("r_skipDeforms", "0", CVAR_CHEAT, "Skip material deformations");
	r_skipAmbient = CVar_Get("r_skipAmbient", "0", CVAR_CHEAT, "Skip rendering ambient stages");
	r_skipBump = CVar_Get("r_skipBump", "0", CVAR_CHEAT, "Skip rendering bump stages");
	r_skipDiffuse = CVar_Get("r_skipDiffuse", "0", CVAR_CHEAT, "Skip rendering diffuse stages");
	r_skipSpecular = CVar_Get("r_skipSpecular", "0", CVAR_CHEAT, "Skip rendering specular stages");
	r_skipShadows = CVar_Get("r_skipShadows", "0", CVAR_CHEAT, "Skip rendering stencil shadows");
	r_skipInteractions = CVar_Get("r_skipInteractions", "0", CVAR_CHEAT, "Skip rendering light-surface interactions");
	r_skipFogLights = CVar_Get("r_skipFogLights", "0", CVAR_CHEAT, "Skip rendering fog lights");
	r_skipBlendLights = CVar_Get("r_skipBlendLights", "0", CVAR_CHEAT, "Skip rendering blend lights");
	r_skipTranslucent = CVar_Get("r_skipTranslucent", "0", CVAR_CHEAT, "Skip rendering translucent materials");
	r_skipPostProcess = CVar_Get("r_skipPostProcess", "0", CVAR_CHEAT, "Skip rendering post-process materials");
	r_skipScissors = CVar_Get("r_skipScissors", "0", CVAR_CHEAT, "Skip scissor testing when rendering lights");
	r_skipDepthBounds = CVar_Get("r_skipDepthBounds", "0", CVAR_CHEAT, "Skip depth bounds testing when rendering lights");
	r_skipPortalSky = CVar_Get("r_skipPortalSky", "0", CVAR_CHEAT, "Skip rendering the portal sky");
	r_skipSubviews = CVar_Get("r_skipSubviews", "0", CVAR_CHEAT, "Skip rendering subviews (mirrors/portals/cameras)");
	r_skipVideos = CVar_Get("r_skipVideos", "0", CVAR_CHEAT, "Skip decoding videos");
	r_skipCopyToTextures = CVar_Get("r_skipCopyToTextures", "0", CVAR_CHEAT, "Skip copying the framebuffer to textures");
	r_skipDynamicTextures = CVar_Get("r_skipDynamicTextures", "0", CVAR_CHEAT, "Skip updating dynamically generated textures");
	r_skipRender = CVar_Get("r_skipRender", "0", CVAR_CHEAT, "Skip rendering 3D views");
	r_skipRenderContext = CVar_Get("r_skipRenderContext", "0", CVAR_CHEAT, "Skip all GL calls for testing CPU performance");
	r_skipFrontEnd = CVar_Get("r_skipFrontEnd", "0", CVAR_CHEAT, "Skip all front-end work");
	r_skipBackEnd = CVar_Get("r_skipBackEnd", "0", CVAR_CHEAT, "Skip all back-end work");
	r_glDriver = CVar_Get("r_glDriver", GL_DRIVER_OPENGL, CVAR_ARCHIVE | CVAR_LATCH, "GL driver");
	r_ignoreGLErrors = CVar_Get("r_ignoreGLErrors", "1", CVAR_ARCHIVE, "Ignore GL errors");
	r_multiSamples = CVar_Get("r_multiSamples", "0", CVAR_ARCHIVE | CVAR_LATCH, "Number of samples for multisample antialiasing");
	r_alphaToCoverage = CVar_Get("r_alphaToCoverage", "0", CVAR_ARCHIVE, "Sample alpha to coverage when multisampling");
	r_swapInterval = CVar_Get("r_swapInterval", "0", CVAR_ARCHIVE, "Sync to the display's refresh rate");
	r_mode = CVar_Get("r_mode", "3", CVAR_ARCHIVE | CVAR_LATCH, "Video mode index for setting screen resolution");
	r_fullscreen = CVar_Get("r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH, "Switch between fullscreen and windowed video mode");
	r_customWidth = CVar_Get("r_customWidth", "720", CVAR_ARCHIVE | CVAR_LATCH, "Screen width when r_mode is set to -1");
	r_customHeight = CVar_Get("r_customHeight", "576", CVAR_ARCHIVE | CVAR_LATCH, "Screen height when r_mode is set to -1");
	r_displayRefresh = CVar_Get("r_displayRefresh", "0", CVAR_ARCHIVE | CVAR_LATCH, "Optional display refresh rate");
	r_gamma = CVar_Get("r_gamma", "1.0", CVAR_ARCHIVE, "Set the device gamma ramp");
	r_brightness = CVar_Get("r_brightness", "1.0", CVAR_ARCHIVE, "Set the device gamma ramp");
	r_finish = CVar_Get("r_finish", "0", CVAR_ARCHIVE, "Sync CPU and GPU every frame");
	r_vertexBuffers = CVar_Get("r_vertexBuffers", "1", CVAR_ARCHIVE | CVAR_LATCH, "Store geometry in vertex buffers");
	r_bloom = CVar_Get("r_bloom", "1", CVAR_ARCHIVE, "Render bloom effects");
	r_bloomContrast = CVar_Get("r_bloomContrast", "1", CVAR_ARCHIVE, "Enhance bloom contrast");
	r_bloomMagnitude = CVar_Get("r_bloomMagnitude", "1.0", CVAR_ARCHIVE, "Bloom blurring magnitude");
	r_bloomIntensity = CVar_Get("r_bloomIntensity", "0.5", CVAR_ARCHIVE, "Bloom blending intensity");
	r_lightScale = CVar_Get("r_lightScale", "2.0", CVAR_ARCHIVE, "Light intensity scale factor");
	r_lightDetailLevel = CVar_Get("r_lightDetailLevel", "2", CVAR_ARCHIVE, "Light detail level (0 = low, 1 = medium, 2 = high)");
	r_shaderPrograms = CVar_Get("r_shaderPrograms", "1", CVAR_ARCHIVE, "Render shader programs");
	r_shaderDetailLevel = CVar_Get("r_shaderDetailLevel", "2", CVAR_ARCHIVE, "Shader detail level (0 = low, 1 = medium, 2 = high)");
	r_roundTexturesDown = CVar_Get("r_roundTexturesDown", "0", CVAR_ARCHIVE | CVAR_LATCH, "Down size non-power of two textures");
	r_maxTextureSize = CVar_Get("r_maxTextureSize", "0", CVAR_ARCHIVE | CVAR_LATCH, "Maximum texture size (0 = default size)");
	r_compressTextures = CVar_Get("r_compressTextures", "0", CVAR_ARCHIVE | CVAR_LATCH, "Compress textures (1 = diffuse/specular textures, 2 = also normal textures)");
	r_textureFilter = CVar_Get("r_textureFilter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE, "Filtering mode for mipmapped textures");
	r_textureLODBias = CVar_Get("r_textureLODBias", "0.0", CVAR_ARCHIVE, "LOD bias for mipmapped textures");
	r_textureAnisotropy = CVar_Get("r_textureAnisotropy", "1.0", CVAR_ARCHIVE, "Anisotropic filtering level for mipmapped textures");

	Cmd_AddCommand("benchmark", R_Benchmark_f, "Benchmarks");
	Cmd_AddCommand("listVideoModes", R_ListVideoModes_f, "Lists video modes");
	Cmd_AddCommand("gfxInfo", R_GfxInfo_f, "Shows graphics information");
}

/*
 ==================
 R_Unregister
 ==================
*/
static void R_Unregister (void){

	Cmd_RemoveCommand("benchmark");
	Cmd_RemoveCommand("listVideoModes");
	Cmd_RemoveCommand("gfxInfo");
}

/*
 ==================
 R_Init
 ==================
*/
void R_Init (bool all){

	Com_Printf("------- Renderer Initialization -------\n");

	if (all){
		R_Register();

		GLImp_Init();
	}

	// Allocate draw meshes and lights
	tr.view.drawMeshes = (drawMesh_t *)Mem_Alloc(MAX_DRAW_MESHES * sizeof(drawMesh_t), TAG_RENDERER);
	tr.view.drawPostProcessMeshes = (drawMesh_t *)Mem_Alloc(MAX_DRAW_POST_PROCESS_MESHES * sizeof(drawMesh_t), TAG_RENDERER);
	tr.view.drawLights = (drawLight_t *)Mem_Alloc(MAX_DRAW_LIGHTS * sizeof(drawLight_t), TAG_RENDERER);
	tr.view.drawFogLights = (drawLight_t *)Mem_Alloc(MAX_DRAW_FOG_LIGHTS * sizeof(drawLight_t), TAG_RENDERER);

	// Clear view cluster
	tr.viewCluster = -1;

	// Clear area bits
	memset(tr.areaBits, 0xFF, sizeof(tr.areaBits));

	// Set default GL state
	GL_SetDefaultState();

	// Set the gamma ramp
	R_SetGamma();

	// Initialize all the renderer modules
	R_InitVertexBuffers();
	R_InitTextures();
	R_InitVideos();
	R_InitShaders();
	R_InitPrograms();
	R_InitTables();
	R_InitMaterials();
	R_InitModels();

	RB_InitBackEnd();

	if (!r_ignoreGLErrors->integerValue)
		GL_CheckForErrors();

	Com_Printf("---------------------------------------\n");
}

/*
 ==================
 R_Shutdown
 ==================
*/
void R_Shutdown (bool all){

	if (!glConfig.initialized)
		return;

	RB_ShutdownBackEnd();

	R_ShutdownModels();
	R_ShutdownMaterials();
	R_ShutdownTables();
	R_ShutdownPrograms();
	R_ShutdownShaders();
	R_ShutdownVideos();
	R_ShutdownTextures();
	R_ShutdownVertexBuffers();

	if (all){
		R_Unregister();

		GLImp_Shutdown();
	}

	Mem_TagFree(TAG_RENDERER);

	memset(&tr, 0, sizeof(trGlobals_t));
}
